package com.facebook.datasource;

import com.facebook.common.executors.CallerThreadExecutor;
import com.facebook.common.internal.Preconditions;
import com.facebook.common.internal.Supplier;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;

@ThreadSafe
public final class IncreasingQualityDataSourceSupplier<T> implements Supplier<AbstractDataSource<T>> {
    @ThreadSafe
    final class IncreasingQualityDataSource extends AbstractDataSource<T> {
        final class InternalDataSubscriber implements DataSubscriber<T> {
            private int mIndex;

            public InternalDataSubscriber(int index) {
                this.mIndex = index;
            }

            public final void onNewResult(AbstractDataSource<T> dataSource) {
                if (dataSource.hasResult()) {
                    boolean isFinished = dataSource.isFinished();
                    synchronized (IncreasingQualityDataSource.this) {
                        int indexOfDataSourceWithResult = IncreasingQualityDataSource.this.mIndexOfDataSourceWithResult;
                        int indexOfDataSourceWithResult1 = IncreasingQualityDataSource.this.mIndexOfDataSourceWithResult;
                        if (dataSource != IncreasingQualityDataSource.this.getDataSource(mIndex)) {
                        } else if (mIndex != IncreasingQualityDataSource.this.mIndexOfDataSourceWithResult) {
                            if (getDataSourceWithResult() == null
                                    || isFinished
                                    && mIndex < IncreasingQualityDataSource.this.mIndexOfDataSourceWithResult) {
                                IncreasingQualityDataSource.this.mIndexOfDataSourceWithResult = mIndex;
                                indexOfDataSourceWithResult1 = mIndex;
                            }
                            while (true) {
                                if (indexOfDataSourceWithResult <= indexOfDataSourceWithResult1) {
                                    break;
                                }
                                IncreasingQualityDataSource.this.closeSafely(IncreasingQualityDataSource.this.getAndClearDataSource(indexOfDataSourceWithResult));
                                --indexOfDataSourceWithResult;
                            }
                        }
                    }
                    if (dataSource != getDataSourceWithResult()) {
                        return;
                    }
                    boolean z = mIndex == 0 && dataSource.isFinished();
                    IncreasingQualityDataSource.this.setResult(null, z);
                } else if (dataSource.isFinished()) {
                    IncreasingQualityDataSource.this.onDataSourceFailed(this.mIndex, dataSource);
                }
            }

            public final void onFailure(AbstractDataSource<T> dataSource) {
                IncreasingQualityDataSource.this.onDataSourceFailed(this.mIndex, dataSource);
            }
        }

        @GuardedBy(value = "IncreasingQualityDataSource.this")
        int mIndexOfDataSourceWithResult;
        @Nullable
        @GuardedBy(value = "IncreasingQualityDataSource.this")
        private ArrayList<AbstractDataSource<T>> mDataSources;

        public IncreasingQualityDataSource(IncreasingQualityDataSourceSupplier<T> increasingQualityDataSourceSupplier) {
            int size = increasingQualityDataSourceSupplier.mDataSourceSuppliers.size();
            this.mIndexOfDataSourceWithResult = size;
            this.mDataSources = new ArrayList(size);
            for (int i = 0; i < size; ++i) {
                Supplier<AbstractDataSource<T>> supplier = increasingQualityDataSourceSupplier.mDataSourceSuppliers.get(i);
                AbstractDataSource<T> dataSource = supplier.get();
                this.mDataSources.add(dataSource);
                dataSource.subscribe(new InternalDataSubscriber(i), CallerThreadExecutor.getInstance());
                if (dataSource.hasResult()) {
                    return;
                }
            }
        }

        @Nullable
        private synchronized AbstractDataSource tryGetAndClearDataSource(int i, AbstractDataSource dataSource) {
            if (dataSource == this.getDataSourceWithResult()) {
                return null;
            } else {
                if (dataSource == this.getDataSource(i)) {
                    dataSource = this.getAndClearDataSource(i);
                }
                return dataSource;
            }
        }

        @Nullable
        final synchronized AbstractDataSource getDataSource(int index) {
            if (this.mDataSources == null) {
                return null;
            } else if (index < this.mDataSources.size()) {
                return this.mDataSources.get(index);
            } else {
                return null;
            }
        }

        void closeSafely(AbstractDataSource<T> dataSource) {
            if (dataSource != null) {
                dataSource.close();
            }
        }

        void onDataSourceFailed(int index, AbstractDataSource<T> dataSource) {
            closeSafely(tryGetAndClearDataSource(index, dataSource));
            if (index == 0) {
                setFailure(dataSource.getFailureCause());
            }
        }

        @Nullable
        public final T getResult() {
            synchronized (this) {
                AbstractDataSource<T> dataSource = getDataSourceWithResult();
                if (dataSource != null) {
                    return dataSource.getResult();
                } else {
                    return null;
                }
            }
        }

        @Nullable
        final synchronized AbstractDataSource<T> getAndClearDataSource(int i) {
            if (this.mDataSources != null && i < this.mDataSources.size()) {
                return this.mDataSources.set(i, null);
            }
            return null;
        }

        public final synchronized boolean hasResult() {
            AbstractDataSource<T> dataSourceWithResult = this.getDataSourceWithResult();
            if (dataSourceWithResult == null) {
                return false;
            } else if (!dataSourceWithResult.hasResult()) {
                return false;
            }
            return true;
        }

        public synchronized final boolean close() {
            if (!super.close()) {
                return false;
            } else {
                ArrayList<AbstractDataSource<T>> copy = this.mDataSources;
                this.mDataSources = null;
                if (copy != null) {
                    for (int i = 0; i < copy.size(); ++i) {
                        closeSafely(copy.get(i));
                    }
                    return true;
                }
                return true;
            }
        }

        @Nullable
        final synchronized AbstractDataSource<T> getDataSourceWithResult() {
            synchronized (this) {
                return this.getDataSource(this.mIndexOfDataSourceWithResult);
            }
        }

    }

    final List<Supplier<AbstractDataSource<T>>> mDataSourceSuppliers;

    public IncreasingQualityDataSourceSupplier(List<Supplier<AbstractDataSource<T>>> supplierList) {
        Preconditions.checkArgument(!supplierList.isEmpty(), "List of suppliers is empty!");
        this.mDataSourceSuppliers = supplierList;
    }

    public final AbstractDataSource<T> get() {
        return new IncreasingQualityDataSource(this);
    }

    public final boolean equals(Object obj) {
        if (obj == this) {
            return true;
        } else if (!(obj instanceof IncreasingQualityDataSourceSupplier)) {
            return false;
        } else {
            return android.support.design.a.equal(this.mDataSourceSuppliers, ((IncreasingQualityDataSourceSupplier) obj).mDataSourceSuppliers);
        }
    }

    public final int hashCode() {
        return this.mDataSourceSuppliers.hashCode();
    }

    public final String toString() {
        return android.support.design.a.toStringHelper(this).add("list", this.mDataSourceSuppliers).toString();
    }
}

